package com.hxgis.common.utils;


import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

/**
 * @author BLQ
 * @date 2019/8/16 11:39
 */
public class Smooth {
    private static int snum = 20;
    private static double sval =0.7;
    public static List<Point2D> smooth(List<Point2D> p2dList) {
        List<Point2D> smList = new ArrayList<>();
        int num = p2dList.size();
        if (num <= 2) {
            smList = p2dList;
        } else {
            Point2D[] ctrls = getControl(p2dList.get(p2dList.size()-1),p2dList.get(0),p2dList.get(1),p2dList.get(2),sval);
            smList.add(ctrls[0]);
            smList.add(ctrls[1]);
//            smList.addAll(smooth(p2dList.get(0),ctrls[0],ctrls[1],p2dList.get(1),snum,sval));
            for (int i = 1; i < p2dList.size(); i++) {
                ctrls = getControl(p2dList.get((i-1)%num)
                        ,p2dList.get(i%num)
                        ,p2dList.get((i+1)%num)
                        ,p2dList.get((i+2)%num)
                        ,sval);
                smList.add(ctrls[0]);
                smList.add(ctrls[1]);
//                smList.addAll(smooth(p2dList.get(i%num)
//                        ,ctrls[0],ctrls[1]
//                        ,p2dList.get((i+1)%num)
//                        ,snum,sval));
            }
//            smList.add(p2dList.get(0));
        }
        return smList;
    }

    private static Point2D[] getControl(Point2D p0, Point2D p1, Point2D p2, Point2D p3, double smooth_value) {
        double x0 = p0.getX();
        double y0 = p0.getY();
        double x1 = p1.getX();
        double y1 = p1.getY();
        double x2 = p2.getX();
        double y2 = p2.getY();
        double x3 = p3.getX();
        double y3 = p3.getY();
        double xc1 = (x0 + x1) / 2.0;
        double yc1 = (y0 + y1) / 2.0;
        double xc2 = (x1 + x2) / 2.0;
        double yc2 = (y1 + y2) / 2.0;
        double xc3 = (x2 + x3) / 2.0;
        double yc3 = (y2 + y3) / 2.0;
        double len1 = Math.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
        double len2 = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
        double len3 = Math.sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2));
        double k1 = len1 / (len1 + len2);
        double k2 = len2 / (len2 + len3);
        double xm1 = xc1 + (xc2 - xc1) * k1;
        double ym1 = yc1 + (yc2 - yc1) * k1;
        double xm2 = xc2 + (xc3 - xc2) * k2;
        double ym2 = yc2 + (yc3 - yc2) * k2;
        double ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
        double ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
        double ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
        double ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
        Point2D[] ctrls = new Point2D[2];
        ctrls[0] = new Point2D.Double(ctrl1_x, ctrl1_y);
        ctrls[1] = new Point2D.Double(ctrl2_x, ctrl2_y);

        return ctrls;
    }



    private static List<Point2D> smooth(Point2D p0, Point2D p1, Point2D p2, Point2D p3,int num, double tick) {
        List<Point2D> smList = new ArrayList<>();
        double t = tick / (num - 1);
        for (int i = 0; i < num; i++) {
            Point2D point = getBezierNowPoint(p0, p1, p2, p3, i, t);
            smList.add(point);
        }
        return smList;
    }

    private static Point2D getBezierNowPoint(Point2D p0,Point2D  p1,Point2D  p2,Point2D  p3,int num, double tick) {
        return new Point2D.Double(Bezier(p0.getX(), p1.getX(), p2.getX(), p3.getX(), num * tick),
                Bezier(p0.getY(), p1.getY(), p2.getY(), p3.getY(), num * tick));

    }

    private static double Bezier(double p0,double  p1, double p2, double p3, double t) {

        double P0 = p0 * (Math.pow((1 - t), 3));
        double P1 = 3 * p1 * t * (Math.pow((1 - t), 2));
        double P2 = 3 * p2 * Math.pow(t, 2) * (1 - t);
        double P3 = p3 * Math.pow(t, 3);

        return P0 + P1 + P2 + P3;
    }
}
